﻿package 
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;	
	import flash.events.Event;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.media.Camera;
	import flash.media.Video;
	import flash.text.TextField;
	import flash.utils.setInterval;

	/*
	 * coded by moka 2009 / 07/ 20 
	 * name : moka's virtual button 
	 * installation : one webcam (需要一台視訊)
	 * help : use your finger or pen to interactive with virtual buttons (用手指或筆跟虛擬按鈕互動,或是站遠一點用揮手方式互動)
	 * extend develop : some physical interactions like PaRaPara or DDR(use hand) ...etc. (可以思考製作PaRaPara/DDR/或搖鈴森巴)
	 * 
	 * 技術上的問題可以至 http://designplusplus.blogspot.com/ 進行討論
	 */
	
	public class Main extends Sprite 
	{		
		private var bg:Bitmap;
		private var preBuf:BitmapData;
		private var curBuf:BitmapData;
		private var difBuf:BitmapData;
		private var thrBuf:BitmapData;
		private var cam:Camera;
		private var vid:Video;
		private var virBtn:Sprite;
		
		public function Main():void 
		{			
			// stage setting (場景不變形)
			stage.scaleMode = "noScale";
			
			// image initialization (點陣圖初始化)
			bg = addChild(new Bitmap(new BitmapData(640, 480, false, 0))) as Bitmap;			
			preBuf = new BitmapData(160, 120, false);
			curBuf = preBuf.clone();
			thrBuf = preBuf.clone();
			
			// camera setting (視訊初始化)
			cam = Camera.getCamera();
			cam.setMode(160, 120, 15);
			vid = new Video(160, 120);
			vid.attachCamera(cam);
			
			// virtual button image (虛擬按鈕繪製)
			virBtn = new Sprite();
			virBtn.graphics.lineStyle(2, 0xFFFFFF);
			virBtn.graphics.drawCircle(0, 0, 5);			
			
			// information (資訊顯示)
			var info:TextField = addChild(new TextField()) as TextField;
			info.textColor = 0xFFFFFF;
			info.x = 10;
			info.y = 280;
			info.width = 300;
			info.htmlText = "<font size='24'>5</font> virtual buttons for testing"
			
			// Moka's work 2009
			var moka:TextField = addChild(new TextField()) as TextField
			moka.x = 35;
			moka.y = 260;
			moka.htmlText = "<font color='#FFFFFF'>Moka's work 2009</font>";
			
			/* I think using the timer is mush better,
			   because the capture speed of camera is slow.
			  (由於視訊捕捉速率慢,因此設計 Timer 來繪製視訊圖片) */			
			
			setInterval(onTimer, 2000 / cam.fps); //(平均一秒繪製7.5次)
			
			//event registration (事件註冊)
			stage.addEventListener(Event.ENTER_FRAME, onProcess)
		}		
		private function onTimer():void {
			// arrange on top (上半部)
			
			// 1.draw pre image to bg (繪製前一張影像)
			bg.bitmapData.draw(preBuf);
			// 2.draw current image to bg (繪製目前影像)
			curBuf.draw(vid);
			bg.bitmapData.draw(curBuf, new Matrix(1, 0, 0, 1, 160));
			// 3.draw difference image to bg (繪製2圖間不同部分(兩圖之間的動量))
			difBuf = curBuf.clone();
			difBuf.draw(preBuf, new Matrix, new ColorTransform, "difference");
			bg.bitmapData.draw(difBuf, new Matrix(1, 0, 0, 1, 320));
			// 4.threshold difference image,fill white color,and draw image to bg 
			// (差異圖像的閥值設定與填色於超越閥值之像素。室內光源越亮閥值要設越高喔)
			difBuf.threshold(difBuf, difBuf.rect, new Point, ">", 0xFF0F0F0F, 0xFFFFFFFF);
			thrBuf.draw(difBuf);
			bg.bitmapData.draw(difBuf, new Matrix(1, 0, 0, 1, 480));
			
			preBuf = curBuf.clone();
		}
		
		private function onProcess(e:Event):void {	
			// arrange on bottom (下半部)
			
			// the big red video image for displaying interaction (紅色影像部分)	
			var displayStartX:Number = 160;
			var displayStartY:Number = 120;
			var displayScale:Number = 3;
			bg.bitmapData.draw(vid, new Matrix(displayScale, 0, 0, displayScale, displayStartX, displayStartY), new ColorTransform(0.5, 0.1, 0.1));
			
			//arrange virtual buttons (排列虛擬按鈕)
			for (var i:uint = 0; i < 5; i++ )
			{
				var thrX:Number = 20+30*i;
				var thrY:Number = 10;
				var virBtnX:Number = displayStartX + displayScale * thrX;
				var virBtnY:Number = displayStartY + displayScale * thrY;			
				
				// hitTest the threshold image and draw virtual buttons (偵測閥值圖像(onTimer步驟4)的顏色(白色)是否碰撞於虛擬按鈕的座標)				
				// 如果覺得常常偵測不到,可以多個偵測點聚集成一個群組(像是把點圍成一個小圈圈)來偵測,群組內只要有某一點碰撞時即觸發事件
				if (thrBuf.getPixel(thrX, thrY) == 0xFFFFFF) {
					bg.bitmapData.draw(virBtn, new Matrix(1.5, 0, 0, 1.5, virBtnX, virBtnY), new ColorTransform(1, 1, 1, 1));
				}else {
					bg.bitmapData.draw(virBtn, new Matrix(1, 0, 0, 1, virBtnX, virBtnY), new ColorTransform(1, 1, 1, 0.3));
				}
			}				
		}
	}		
}